// MdSpi.cpp: implementation of the CMdSpi class.
//
//////////////////////////////////////////////////////////////////////

#include "MdSpi.h"

#include <sys/stat.h>
#include <sys/types.h>

#include "TradeSpi.h"

extern vector<IPolicy *> *g_policy;
#define CTP_LIKE
// #define CTP_NO_LIKE
IFutureMD *CreateMD(const char *pszConfigFile) {
  CMdSpi2 *pMdSpi = new CMdSpi2(pszConfigFile);
  pMdSpi->InitMyConfig(pszConfigFile);

  CCtpFutureMD *pMd = new CCtpFutureMD();
  pMd->m_pSpi = pMdSpi;
  pMdSpi->m_pMd = pMd;

  return pMd;
}

void *CheckThreadProc(void *lParam) {
  /*CMdSpi2* pSpi = (CMdSpi2*)lParam;
  while(true){
      pthread_testcancel();
      sleep(1);
      pSpi->Check();
  }
  pthread_detach(pthread_self());*/
  return 0;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CMdSpi2::CMdSpi2()  // todo:m_Config(pszInitFile)
{
  printf("CMdSpi2() call \n");
  // EqsTcpInfo			info;
  // vector<EqsTcpInfo>	vec_info;
  //
  // memset(&info, 0, sizeof(EqsTcpInfo));
  // strcpy(info.m_eqsIp, "183.129.220.106");
  // info.m_eqsPort = 60006;
  // vec_info.push_back(info);
  //
  // int ret = m_pMdApi->ConnServer(vec_info, this);
  // if (!ret)
  //{
  //	printf("Connect Quote Server Failed!\n");
  //
  //}
  // else
  //{
  //	printf("Connect Quote Server OK!\n");
  //}

  m_cIniFile[0] = '\0';
  m_bOnline = false;
  m_pMdApi = NULL;
  m_pAllMarketData3 = NULL;
  m_pConfig3 = NULL;
  for (int i = 0; i < REM_MD_BUFFER_SIZE; i++) {
    m_buffer[i] = {};
  }
  m_idx = 0;

  // pthread_create(&m_pthread,NULL,CheckThreadProc,(void *)this);
}

CMdSpi2::CMdSpi2(const char *pszInitFile)  // todo:m_Config(pszInitFile)
{
  printf("CMdSpi2() call with paramer \n");
  // EqsTcpInfo			info;
  // vector<EqsTcpInfo>	vec_info;

  // memset(&info, 0, sizeof(EqsTcpInfo));
  // strcpy(info.m_eqsIp, "183.129.220.106");
  // info.m_eqsPort = 60006;
  // vec_info.push_back(info);

  // int ret = m_pMdApi->ConnServer(vec_info, this);
  // if (!ret)
  //{
  //	printf("Connect Quote Server Failed!\n");
  // }
  // else
  //{
  //	printf("Connect Quote Server OK!\n");
  // }

  strcpy(m_cIniFile, pszInitFile);
  m_bOnline = false;
  m_pMdApi = NULL;
  m_pAllMarketData3 = NULL;
  m_pConfig3 = NULL;
  // pthread_create(&m_pthread,NULL,CheckThreadProc,(void *)this);
}

CMdSpi2::~CMdSpi2() {
  pthread_cancel(m_pthread);
  sleep(2);

  delete m_pAllMarketData3;
  delete m_pConfig3;
}

void CMdSpi2::OnEqsConnected() {
  SPDLOG_INFO(" MD ------- OnEqsConnected");
  EqsLoginParam temp;

  strcpy(temp.m_loginId, m_pConfig3->GetUser());
  strcpy(temp.m_password, m_pConfig3->GetPassword());

  SPDLOG_INFO("MD Login Id {}", temp.m_loginId);
  SPDLOG_INFO("MD Login Pwd {}", temp.m_password);

  if (!m_pMdApi) {
    printf("Invalid Quote Api Instance\n");
    return;
  }

  m_pMdApi->LoginToEqs(temp);
}

inline bool CopyMD_CTP(MarketDataField *pData,
                       CThostFtdcDepthMarketDataField *pField) {
  pField->OpenPrice = pData->OpenPrice;
  pField->LastPrice = pData->LastPrice;

  pField->BidPrice1 = pData->BidPrice[0];
  pField->AskPrice1 = pData->AskPrice[0];
  pField->BidVolume1 = pData->BidVolume[0];
  pField->AskVolume1 = pData->AskVolume[0];

  pField->BidPrice2 = pData->BidPrice[1];
  pField->AskPrice2 = pData->AskPrice[1];
  pField->BidVolume2 = pData->BidVolume[1];
  pField->AskVolume2 = pData->AskVolume[1];

  pField->BidPrice3 = pData->BidPrice[2];
  pField->AskPrice3 = pData->AskPrice[2];
  pField->BidVolume3 = pData->BidVolume[2];
  pField->AskVolume3 = pData->AskVolume[2];

  pField->BidPrice4 = pData->BidPrice[3];
  pField->AskPrice4 = pData->AskPrice[3];
  pField->BidVolume4 = pData->BidVolume[3];
  pField->AskVolume4 = pData->AskVolume[3];

  pField->BidPrice5 = pData->BidPrice[4];
  pField->AskPrice5 = pData->AskPrice[4];
  pField->BidVolume5 = pData->BidVolume[4];
  pField->AskVolume5 = pData->AskVolume[4];

  pField->Turnover = pData->Ammount;
  pField->OpenInterest = pData->OpenInterest;
  pField->Volume = pData->Volume;
  pField->HighestPrice = pData->HighestPrice;
  pField->LowestPrice = pData->LowestPrice;
  // pData->SettlementPrice = pField->SettlementPrice;
  // strcpy(pData->UpdateTime, pField->UpdateTime);
  strcpy(pField->UpdateTime, pData->UpdateTime);
  strcpy(pField->InstrumentID, pData->InstrumentID);

  /*
    // added 2013-12-20
    if (pData->UpdateTime[0] == '2') {
      pData->UpdateTime[0] = '0';
      if (pData->UpdateTime[1] >= '1') {
        pData->UpdateTime[1]--;
      } else {
        return false;
      }
    } else if (pData->UpdateTime[0] == '0' && pData->UpdateTime[1] <= '3') {
      pData->UpdateTime[1] += 3;
    }
  */
  pField->UpdateMillisec = pData->MilliSeconds;
  pField->SettlementPrice = pData->AveragePrice;
  return true;
}

bool CMdSpi2::CopyMD(MarketDataField *pData, EESMarketDepthQuoteData *pField) {
  pData->OpenPrice = pField->OpenPrice;
  pData->LastPrice = pField->LastPrice;

  pData->BidPrice[0] = pField->BidPrice1;
  pData->AskPrice[0] = pField->AskPrice1;
  pData->BidVolume[0] = pField->BidVolume1;
  pData->AskVolume[0] = pField->AskVolume1;

  pData->BidPrice[1] = pField->BidPrice2;
  pData->AskPrice[1] = pField->AskPrice2;
  pData->BidVolume[1] = pField->BidVolume2;
  pData->AskVolume[1] = pField->AskVolume2;

  pData->BidPrice[2] = pField->BidPrice3;
  pData->AskPrice[2] = pField->AskPrice3;
  pData->BidVolume[2] = pField->BidVolume3;
  pData->AskVolume[2] = pField->AskVolume3;

  pData->BidPrice[3] = pField->BidPrice4;
  pData->AskPrice[3] = pField->AskPrice4;
  pData->BidVolume[3] = pField->BidVolume4;
  pData->AskVolume[3] = pField->AskVolume4;

  pData->BidPrice[4] = pField->BidPrice5;
  pData->AskPrice[4] = pField->AskPrice5;
  pData->BidVolume[4] = pField->BidVolume5;
  pData->AskVolume[4] = pField->AskVolume5;

  pData->Ammount = pField->Turnover;
  pData->OpenInterest = pField->OpenInterest;
  pData->Volume = pField->Volume;
  pData->HighestPrice = pField->HighestPrice;
  pData->LowestPrice = pField->LowestPrice;
  pData->LowerLimitPrice = pField->LowerLimitPrice;
  pData->UpperLimitPrice = pField->UpperLimitPrice;
  strcpy(pData->TradingDay, pField->TradingDay);
  // printf("trade dasty %s \n", pData->TradingDay);
  //   pData->SettlementPrice = pField->SettlementPrice;
  strcpy(pData->UpdateTime, pField->UpdateTime);
  // memset(pData->UpdateTime, 0, 10);
  // memcpy(pData->UpdateTime, pField->UpdateTime, 9);
  strcpy(pData->InstrumentID, pField->InstrumentID);
  // printf("--- >  %s", pData->UpdateTime);
  /*
    // added 2013-12-20
    if (pData->UpdateTime[0] == '2') {
      pData->UpdateTime[0] = '0';
      if (pData->UpdateTime[1] >= '1') {
        pData->UpdateTime[1]--;
      } else {
        return false;
      }
    } else if (pData->UpdateTime[0] == '0' && pData->UpdateTime[1] <= '3') {
      pData->UpdateTime[1] += 3;
    }
    */

  pData->MilliSeconds = pField->UpdateMillisec;
  pData->AveragePrice = pField->SettlementPrice;
  return true;
}

void CMdSpi2::OnQuoteUpdated(EesEqsIntrumentType chInstrumentType,
                             EESMarketDepthQuoteData *pDepthQuoteData) {
  int idx = m_idx++ % REM_MD_BUFFER_SIZE;
  m_buffer[idx];
  // printf("in in in  %s\n", pDepthQuoteData->TradingDay);
  //  MarketDataField data = {};
  //  MarketDataField *pData = &data;
  //  CThostFtdcDepthMarketDataField ctp_data = {};
  //  CThostFtdcDepthMarketDataField *p_ctp_data = &ctp_data;

  // printf("market data -------------------> ticker %s   time %s \n",
  //        pDepthQuoteData->InstrumentID, pDepthQuoteData->UpdateTime);
  /*
    SPDLOG_INFO("OnQuoteUpdated ticker {}  vol {}  px {}",
                pDepthQuoteData->InstrumentID, pDepthQuoteData->Volume,
                pDepthQuoteData->LastPrice);*/

  CopyMD(&m_buffer[idx], pDepthQuoteData);
  // CopyMD_CTP(pData, p_ctp_data);
  // printf("----------------> ctp 1111  %s \n ", m_buffer[idx].TradingDay);

  // MarketDataField *pData_rlt =
  // m_pAllMarketData3->AddMarketDataField(p_ctp_data);
  //  printf("----------------> ctp  %s \n ", pData_rlt->InstrumentID);
  if (pDepthQuoteData != NULL) {
    m_ListenerLock.Lock();
    list<IMarketDataListener *>::iterator it = m_Listeners.begin();
    list<IMarketDataListener *>::iterator end = m_Listeners.end();
    while (it != end) {
      // SPDLOG_INFO("call listener md ");
      IMarketDataListener *pListener = *it;
#ifdef CTP_LIKE
      pListener->OnFutureMarketData(&m_buffer[idx]);
#endif
      it++;
    }
// SPDLOG_INFO("call OnQuoteUpdated ticker {}  vol {}  px {}",
// pData->InstrumentID, pData->Volume, pData->LastPrice);
#ifdef CTP_NO_LIKE
    if (g_policy) {
      SPDLOG_INFO("step 1");
      if ((*g_policy).size() > 0) {
        SPDLOG_INFO("step 2");

        for (auto ele : *g_policy) {
          SPDLOG_INFO("step 3");

          if (ele) {
            ele->OnNewFutureMD(pData);
            SPDLOG_INFO("call OnNewFutureMD ticker {}  vol {}  px {}",
                        pData->InstrumentID, pData->Volume, pData->LastPrice);
          } else {
            SPDLOG_INFO("cant call OnNewFutureMD,  g_policy  is nullptr");
          }
        }
      }
    }
#endif
    m_ListenerLock.Unlock();
  }
}

void CMdSpi2::OnLoginResponse(bool bSuccess, const char *pReason) {
  SPDLOG_INFO("OnLoginResponse  ");

  if (bSuccess) {
    SPDLOG_INFO("md Login Sucess ");
  } else {
    SPDLOG_ERROR("md Login Fail ");
  }
  m_SubLock.Lock();
  m_bOnline = true;
  if (!m_SubScribeCount.empty()) {
    char **ppCodes = new char *[m_SubScribeCount.size()];
    int count = 0;
    map<string, int>::iterator it = m_SubScribeCount.begin();
    map<string, int>::iterator end = m_SubScribeCount.end();
    while (it != end) {
      const char *code = it->first.c_str();
      ppCodes[count] = new char[strlen(code) + 1];
      strcpy(ppCodes[count], code);
      count++;
      it++;
    }
    // to do
    // m_pMdApi->RegisterSymbol(EQS_FUTURE,"au2210");

    for (int i = 0; i < count; i++) {
      delete[] ppCodes[i];
    }

    delete[] ppCodes;
  }
  m_SubLock.Unlock();
  m_nLastError = 0;
  m_cLastError[0] = '\0';
  // m_pMdApi->RegisterSymbol(EQS_FUTURE,"au2210");
  printf("md logined\n");
  m_hEvent.fire();
  printf("md logined end \n");
}

void CMdSpi2::OnSymbolRegisterResponse(EesEqsIntrumentType chInstrumentType,
                                       const char *pSymbol, bool bSuccess) {
  SPDLOG_INFO("OnSymbolRegisterResponse curr register ticker{}", pSymbol);
}

void CMdSpi2::OnEqsDisconnected() {
  SPDLOG_INFO("NOTICE ------------>>>>>MD ----------OnEqsDisconnected");
};

int CMdSpi2::SubscribeMarketData(const char *code) {
  m_pMdApi->RegisterSymbol(EQS_FUTURE, code);
  SPDLOG_INFO("SubscribeMarketData");
  int index = 0;
  char **pNewCodes = new char *[1];
  int nRet = 0;

  m_SubLock.Lock();
  map<string, int>::iterator it = m_SubScribeCount.find(code);
  if (it == m_SubScribeCount.end()) {
    m_SubScribeCount.insert(pair<string, int>(code, 1));
    pNewCodes[index++] = new char[32];
    strcpy(pNewCodes[0], code);
  } else {
    it->second = it->second + 1;
  }

  /*
  if(index >0){
      if(m_bOnline){
          nRet = m_pMdApi->SubscribeMarketData(pNewCodes,index);
          if(nRet != 0){
              printf("subscribe md return non-zero: %s,
  errorid:%d\n",pNewCodes[0],nRet);
          }
      }
      delete[] pNewCodes[0];
  }
*/
  delete[] pNewCodes;

  m_SubLock.Unlock();

  printf("sub md: %s\n", code);

  return nRet;
}

// unscribe market data;
void CMdSpi2::UnsubscribeMarketData(const char *code) {}

void CMdSpi2::InitMyConfig(const char *pszInit) {
  strcpy(m_cIniFile, pszInit);
  m_pConfig3 = new CMyConfig2();
  m_pConfig3->LoadConfig(pszInit);
  m_pAllMarketData3 = new CAllMarketData();
}

int CMdSpi2::Login(const char *UserID, const char *Password, char *ErrorMsg,
                   int *ErrorID) {
  int nCode = Login(UserID, Password);
  *ErrorID = nCode;
  strcpy(ErrorMsg, m_cLastError);
  return nCode;
}

int CMdSpi2::Login(const char *pszUserID, const char *pszPassword) {
  char cDir[64];
  char cServer[128];

  mkdir("./tmp", 0755);
  strcpy(cDir, "./tmp/");
  strcat(cDir, pszUserID);
  strcat(cDir, "_md");
  mkdir(cDir, 0755);
  strcat(cDir, "/");

  m_pConfig3->SetUser(pszUserID);
  m_pConfig3->SetPassword(pszPassword);
  // m_pConfig3->m_MDServers
  m_pMdApi = CreateEESQuoteApi();

  EqsTcpInfo info;
  vector<EqsTcpInfo> vec_info;

  auto md_itr = (*m_pConfig3->m_MDServers["user1"]).begin();
  string md_ip = (*md_itr).substr(0, (*md_itr).find(":"));
  string md_port = (*md_itr).substr((*md_itr).find(":") + 1);

  SPDLOG_INFO("Get Md ip {}", md_ip);
  SPDLOG_INFO("Get Md Port {}", md_port);
  memset(&info, 0, sizeof(EqsTcpInfo));
  strcpy(info.m_eqsIp, md_ip.c_str());
  info.m_eqsPort = stoi(md_port);
  vec_info.push_back(info);

  int ret = m_pMdApi->ConnServer(vec_info, this);
  if (!ret) {
    printf("Connect Quote Server Failed!\n");
  } else {
    printf("Connect Quote Server OK!\n");
  }

  m_hEvent.wait();
  // to do
  sleep(11);
  return 0;
}

void CMdSpi2::AddListener(IMarketDataListener *pListener) {
  SPDLOG_INFO("AddListener");

  m_ListenerLock.Lock();
  m_Listeners.push_back(pListener);
  // pListener->OnSetFutureMD((IFutureMD*)m_pMd);
  m_ListenerLock.Unlock();
}

void CMdSpi2::RemoveListener(IMarketDataListener *pListener) {
  m_ListenerLock.Lock();
  m_Listeners.remove(pListener);
  m_ListenerLock.Unlock();
}

void CMdSpi2::Stop() {
  SPDLOG_INFO("MD Realease call");
  if (m_pMdApi != NULL) {
    m_pMdApi = NULL;
  }
}

void CMdSpi2::Release() {
  SPDLOG_INFO("MD Realease call");
  delete this;
}

/**
 *login to trade;
 */
int CCtpFutureMD::Login(const char *UserID, const char *Password,
                        char *ErrorMsg, int *ErrorID) {
  return m_pSpi->Login(UserID, Password, ErrorMsg, ErrorID);
}

int CCtpFutureMD::SubscribeMarketData(const char *InstrumentID) {
  return m_pSpi->SubscribeMarketData(InstrumentID);
}

void CCtpFutureMD::UnsubscribeMarketData(const char *InstrumentID) {
  m_pSpi->UnsubscribeMarketData(InstrumentID);
}

void CCtpFutureMD::AddListener(IMarketDataListener *pListener) {
  m_pSpi->AddListener(pListener);
}

void CCtpFutureMD::RemoveListener(IMarketDataListener *pListener) {
  m_pSpi->RemoveListener(pListener);
}

void CCtpFutureMD::Stop() { m_pSpi->Stop(); }

void CCtpFutureMD::Release() {
  m_pSpi->Release();
  delete this;
}
